<?php
/**
 *
 * ============================================================================
 * * 版权所有 度拉拉 * *
 * 网站地址: http://www.dlltrip.com
 * ----------------------------------------------------------------------------
 * 这不是一个自由软件！您只能在不用于商业目的的前提下对程序代码进行修改和
 * 使用；不允许对程序代码以任何形式任何目的的再发布。
 * ============================================================================
 * Author By: 倪宗锋
 * PhpStorm WeChatService.php
 * Create By 2017/6/7 11:09 $
 */


namespace common\service;

use common\config\wechatConfig\WxDoFunction;
use common\service\pay\WeChatPay;
use common\util\CurlInterface;
use common\util\Util;

class WeChatService
{
    //配置参数
    private $request = array();
    private $response = false;
    private $token = '';
    private $appid = '';
    private $appsecret = '';

    public function __construct()
    {
        $wxConfig = Util::getWeChatConfig();
        $this->token = $wxConfig['token'];
        $this->appid = $wxConfig['appid'];
        $this->appsecret = $wxConfig['appsecret'];
    }

    /**
     * Des:接收参数并处理返回值
     * Name: exec
     * @return string
     * @author 倪宗锋
     */
    public function exec()
    {
        $content = $this->getContent();//获取参数并解析

        if ($content['MsgType'] == 'text') {
            $this->response = $this->textMsg($content);
        } elseif ($content['MsgType'] == 'event') {
            $this->response = $this->eventMsg($content);
        }
        return $this->response;
    }

    /**
     * Des:用户输入内容处理
     * Name: textMsg
     * @param $content
     * @return bool|string
     * @author 倪宗锋
     */
    public function textMsg($content)
    {
//        $textTpl = "
//<xml>
//<ToUserName><![CDATA[%s]]></ToUserName>
//<FromUserName><![CDATA[%s]]></FromUserName>
//<CreateTime>%s</CreateTime>
//<MsgType><![CDATA[transfer_customer_service]]></MsgType>
//</xml>";
//        $resultStr = sprintf($textTpl, $content['FromUserName'], $content['ToUserName'], time());
//        return $resultStr;
        $word = $content['Content'];
        return $this->send($word, $content, 'text');
    }

    /**
     * Des:推送事件处理
     * Name: eventMsg
     * @param $content
     * @return string
     * @author 倪宗锋
     */
    public function eventMsg($content)
    {
        if ($content['Event'] == 'subscribe') {//微信关注事件 发送欢迎语
            $word = 'subscribe';
        } elseif ($content['Event'] == 'unsubscribe') {//微信关注事件 发送欢迎语
            $word = 'unsubscribe';
        } elseif ($content['Event'] == 'SCAN') {//扫一扫
            $word = 'SCAN';
        } else if ($content['Event'] == 'VIEW' || empty($content['EventKey'])) {
            return false;
        } else {
            $word = $content['EventKey'];
        }
        if ($word == 'MSG_LIANXIKEFU') {
            return $this->callCuster($content);
        }
        return $this->send($word, $content, 'event');

    }

    /**
     * Des:联系客服
     * Name: sendText
     * @param $content
     * @return string
     * @author 倪宗锋
     */
    private function callCuster($content)
    {
        $textTpl = '' . "
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[transfer_customer_service]]></MsgType>
</xml>";
        $resultStr = sprintf($textTpl, $content['FromUserName'], $content['ToUserName'], time());
        return $resultStr;
    }

    /**
     * Des: 发送处理
     * Name: send
     * @param $word
     * @param $content
     * @param string $type 触发类型：text用户输入 event推送事件
     * @return string
     * @author 倪宗锋
     */
    public function send($word, $content, $type = 'text')
    {
        $weChatPayConfig = Util::getWeChatConfig();
        $textConfig = require ROOT_PATH . '/common/config/wechatConfig/wxInterface/' . $weChatPayConfig['mch_id'] . '/Wx.' . $type . '.config.php';
        if (empty($textConfig[$word]) == false) {//如果 有指定的配置就用指定的配置
            $msgSend = $textConfig[$word];
        } else if ($type == 'text') {//没有指定的配置 且 接收的是用户输入文本信息
//            $info = new WxDoFunction();
//            $getDoResult = $info->showOrderInfo($word);//获取订单信息暂时停止 //todo 获取订单信息
//            if ($getDoResult == '') {
//                //默认联系客服
//                $msgSend = $this->callCuster($content);
//                return $msgSend;
//            } else {
//                $msgSend = $getDoResult;
//            }
            //默认联系客服
            $msgSend = $this->callCuster($content);
            return $msgSend;
        } else {//没有指定配置 且接收的是按钮或扫一扫则直接返回关注自动回复信息
            $msgSend = $textConfig['subscribe'];
        }
        if (is_array($msgSend) && empty($msgSend['function']) == false) {//当推送事件有方法指定时，则调用该方法
            $wxDoFunction = new WxDoFunction();
            $function = $msgSend['function'];
            $wxDoFunction->$function($content);
        }
        if (isset($msgSend['type']) && $msgSend['type'] == 'news') {//如果是图文类型
            return $this->sendNews($content, $msgSend['id']);
        } elseif (isset($msgSend['type']) && $msgSend['type'] == 'img') {//如果是图片类型
            return $this->sendImage($content, $msgSend['id']);
        } elseif (isset($msgSend['type']) && $msgSend['type'] == 'voice') {//如果是语音类型
            return $this->sendVoice($content, $msgSend['id']);
        } elseif (isset($msgSend['type']) && $msgSend['type'] == 'video') {//如果是视频类型
            return $this->sendVideo($content, $msgSend);
        } else {
            return $this->sendText($content, $msgSend);
        }
    }

    /**
     * Des:发送文字
     * Name: sendText
     * @param $content
     * @param $msgSend
     * @return string
     * @author 倪宗锋
     */
    private function sendText($content, $msgSend)
    {
        $textTpl = '' . "
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
        $msgType = "text";
        if (is_array($msgSend)) {
            $msgSend = $msgSend['text'];
        }
        $resultStr = sprintf($textTpl, $content['FromUserName'], $content['ToUserName'], time(), $msgType, $msgSend);
        return $resultStr;
    }

    /**
     * Des:发送图文
     * Name: sendNews
     * @param $content array
     * @param $mediaId string 素材图文 ID
     * @return string
     * @author 倪宗锋
     */
    private function sendNews($content, $mediaId)
    {
        $news = $this->getNewsByMediaId($mediaId);
        return $this->transmitNews($content, $news);
    }

    /**
     * Des:发送图片
     * Name: sendImage
     * @param $content
     * @param $mediaId
     * @return string
     * @author 倪宗锋
     */
    private function sendImage($content, $mediaId)
    {
        $xmlTpl = '' . "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>
 </xml>";
        $result = sprintf($xmlTpl, $content['FromUserName'], $content['ToUserName'], time(), $mediaId);
        return $result;
    }

    /**
     * Des:发送语音
     * Name: sendVoice
     * @param $content
     * @param $mediaId
     * @return string
     * @author 倪宗锋
     */
    private function sendVoice($content, $mediaId)
    {
        $xmlTpl = '' . "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[voice]]></MsgType>
<Voice>
<MediaId><![CDATA[%s]]></MediaId>
</Voice>
</xml>";
        $result = sprintf($xmlTpl, $content['FromUserName'], $content['ToUserName'], time(), $mediaId);
        return $result;
    }

    /**
     * Des:发送视频
     * Name: sendVideo
     * @param $content
     * @param $sendMsg
     * @return string
     * @author 倪宗锋
     */
    private function sendVideo($content, $sendMsg)
    {
        $xmlTpl = '' . "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[video]]></MsgType>
<Video>
<MediaId><![CDATA[%s]]></MediaId>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
</Video>
</xml>";
        $result = sprintf($xmlTpl, $content['FromUserName'], $content['ToUserName'], time(), $sendMsg['id'], $sendMsg["title"], $sendMsg["des"]);
        return $result;
    }

    /**
     * Des:根据ID获取图文信息
     * Name: getNewsByMediaId
     * @param $data_media_id
     * @return array
     * @author 倪宗锋
     */
    public function getNewsByMediaId($data_media_id)
    {
        $data_media_id = '{"media_id":"' . $data_media_id . '"}';
        $url = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=" . $this->getAccessToken();
        $response = $this->_requestPost($url, $data_media_id);
        $media = json_decode($response, true);
        $mediaArray = $media['news_item'];
        $content = array();
        foreach ($mediaArray as $k => $v) {
            if ($k == 0 || $k == 1)
                $content[] = array("Title" => $v['title'], "Description" => $v['digest'], "PicUrl" => $v['thumb_url'], "Url" => $v['url']);
            elseif ($k == 2) {
                $content[] = array("Title" => $v['title'], "Description" => $v['digest'], "PicUrl" => $v['thumb_url'], "Url" => $v['content_source_url']);
            } else
                $content[] = array("Title" => $v['title'], "Description" => $v['digest'], "PicUrl" => $v['thumb_url'], "Url" => $v['content_source_url']);
        }
        return $content;
    }

    /**
     * Des:图文推送数据处理
     * Name: transmitNews
     * @param $content
     * @param $newsArray
     * @return string
     * @author 倪宗锋
     */
    private function transmitNews($content, $newsArray)
    {
        if (!is_array($newsArray)) {
            return '';
        }
        $itemTpl = '' . "<item><Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url></item>";
        $item_str = "";
        foreach ($newsArray as $item) {
            $item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
        }
        $xmlTpl = '' . "<xml>
<ToUserName><![CDATA[{$content['FromUserName']}]]></ToUserName>
<FromUserName><![CDATA[{$content['ToUserName']}]]></FromUserName>
<CreateTime>" . time() . "</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>" . count($newsArray) . "</ArticleCount>
<Articles>$item_str</Articles>
</xml>";
        return $xmlTpl;
    }

    /*************************=========第一次请求校验==========***********************************/
    /**
     * Des:第一次校验
     * Name: valid
     * @return bool
     * @author 倪宗锋
     */
    public function valid()
    {
        $echoStr = $_GET["echostr"];
        if ($this->checkSignature()) {
            $this->response = $echoStr;
        }
        return $this->response;
    }

    /***********************************通用函数*******************************************************/
    /**
     * Des:根据openid获取用户信息
     * Name: getUserInfoByOpenid
     * @param $openid
     * @return array
     * @author 倪宗锋
     */
    public static function getUserInfoByOpenid($openid)
    {
        $token = static::getAccessToken();
        $userInfo = static::getWeChatInfo($openid, $token);
        return $userInfo;
    }

    /**
     * Des:通用获取微信用户信息
     * Name: getWeChatInfo
     * @param $openid
     * @param $accessToken string  基础公共access_token
     * @return array
     * @author 倪宗锋
     */
    public static function getWeChatInfo($openid, $accessToken)
    {
        $query = array(
            'access_token' => $accessToken,
            'openid' => $openid,
            'lang' => 'zh_CN'
        );
        $url = "https://api.weixin.qq.com/cgi-bin/user/info?";
        $url .= http_build_query($query);
        $curl = new CurlInterface('', 4);
        $arr = $curl->execute($url);
        $return = [
            'nickname' => $arr['nickname'],
            'headimgurl' => $arr['headimgurl'],
            'sex' => $arr['sex'],
            'country' => $arr['country'],
            'city' => $arr['city'],
            'province' => $arr['province']
        ];
        return $return;
    }

    /**
     * Des:授权登录获取用户信息
     * Name: getAuthWeChatInfo
     * @param $openid
     * @param $accessToken string 授权获取的accessToken
     * @return array
     * @author 倪宗锋
     */
    public static function getAuthWeChatInfo($openid, $accessToken)
    {
        $query = array(
            'access_token' => $accessToken,
            'openid' => $openid,
            'lang' => 'zh_CN'
        );
        $url = "https://api.weixin.qq.com/sns/userinfo?";
        $url .= http_build_query($query);
        $curl = new CurlInterface('', 4);
        $arr = $curl->execute($url);
        $return = [
            'nickname' => $arr['nickname'],
            'headimgurl' => $arr['headimgurl'],
            'sex' => $arr['sex'],
            'country' => $arr['country'],
            'city' => $arr['city'],
            'province' => $arr['province']
        ];
        return $return;
    }

    /**
     * Des:数据校验
     * Name: checkSignature
     * @return bool
     * @author 倪宗锋
     */
    private function checkSignature()
    {
        $token = $this->token;
        $signature = isset($_GET["signature"]) ? $_GET["signature"] : "";
        $timestamp = isset($_GET["timestamp"]) ? $_GET["timestamp"] : "";
        $nonce = isset($_GET["nonce"]) ? $_GET["nonce"] : "";
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);
        if ($tmpStr == $signature) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * Des:参数解析
     * Name: getContent
     * @author 倪宗锋
     */
    private function getContent()
    {
        $content = file_get_contents("php://input");
        libxml_disable_entity_loader(true);
        $this->request = (array)simplexml_load_string($content, 'SimpleXMLElement', LIBXML_NOCDATA);
        return $this->request;
    }

    /**
     * Des:获取token
     * Name: getAccessToken
     * @param $appid
     * @return string
     * @author 倪宗锋
     */
    public static function getAccessToken($appid = '')
    {
        $wxConfig = Util::getWeChatConfig($appid);
        $appid = $wxConfig['appid'];
        $appsecret = $wxConfig['appsecret'];
        $access_token = static::getWxAccessToken($appid, $appsecret);
        return $access_token;
    }

    /**
     * Des:获取指定的微信公众号的token
     * Name: getWxAccessToken
     * @param $appid
     * @param $appsecret
     * @return mixed|string
     * @author 倪宗锋
     */
    public static function getWxAccessToken($appid, $appsecret)
    {
        $key = $appid . 'access_token';
        $memcache = \Yii::$app->getCache();
        $access_token = $memcache->get($key);
        if (empty($access_token)) {
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$appsecret}";
            $getToken = self::_requestGet($url);//发起get请求获取token
            $res = json_decode($getToken, true);//json转换成数组
            if (empty($res['access_token'])) {
                return '';
            }
            $access_token = $res['access_token'];
            $memcache->set($key, $access_token, 3600);
        }
        return $access_token;
    }

    /**
     * Function Description:根据code获取token
     * Function Name: getToken
     * @param $code
     *
     * @return array
     *
     * @author 倪宗锋
     */
    public static function getToken($code)
    {
        $WxPayConfig = Util::getWeChatConfig();
        $siteConfig = Util::getSiteConfig();
        $urlObj["appid"] = $WxPayConfig['appid'];
        $urlObj["secret"] = $WxPayConfig['appsecret'];
        $urlObj["code"] = $code;
        $urlObj["grant_type"] = "authorization_code";
        $bizString = http_build_query($urlObj);
        $url = $siteConfig['authTokenUrl'] . $bizString;
        $curlInterface = new CurlInterface('', 4);
        $curlInterface->setBaseUrl($url);
        $getToken = $curlInterface->execute('', 'GET');
        if (empty($getToken['openid'])) {
            return Util::returnArrEr('参数无效！');
        }
        return Util::returnArrSu('', $getToken);
    }

    /**
     * Des:发起get请求
     * Name: _requestGet
     * @param $url string
     * @param bool|true $ssl
     * @return bool|mixed
     * @author 倪宗锋
     */
    public static function _requestGet($url, $ssl = true)
    {
        $logStr = date('Y-m-d H:i:s') . " Url : ".$url. PHP_EOL;
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_AUTOREFERER, true);
        if ($ssl) {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
        }
        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($curl);
        if ($response === false) {
            return false;
        }
        $logStr = $logStr." response : ".$response. PHP_EOL;
        file_put_contents(APP_PATH . '/log/curl/' . date('Y-m-d') . '.log', $logStr . PHP_EOL, FILE_APPEND);
        return $response;
    }

    /**
     * Des:发起post请求
     * Name: _requestPost
     * @param $url
     * @param $data
     * @param bool|true $ssl
     * @return bool|mixed
     * @author 倪宗锋
     */
    public static function _requestPost($url, $data, $ssl = true)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
        curl_setopt($curl, CURLOPT_USERAGENT, $user_agent);
        curl_setopt($curl, CURLOPT_AUTOREFERER, true);
        if ($ssl) {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
        }
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($curl);
        if ($response === false) {
            return false;
        }
        return $response;
    }

    /**
     * Des:获取
     * Name: httpRequest
     * @param $url
     * @param null $data
     * @return mixed
     * @author 倪宗锋
     */
    static function httpRequest($url, $data = null)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        if (!empty($data)) {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        curl_close($ch);
        return $output;
    }


    /**
     * 分销用户二维码
     */
    public static function getFxQrCode($fx_uid)
    {
        $config = Util::getSiteConfig();
        $imgUrl = ROOT_PATH . '/web/fx/images/FxQrCode/' . $fx_uid . '.png';
        $showUrl = $config['host_name'] . '/web/fx/images/FxQrCode/' . $fx_uid . '.png';
        if (file_exists($imgUrl)) {
            return Util::returnArrSu('', array('url' => $showUrl));
        }
        $logo = ROOT_PATH . '/web/fx/images/logo.png';
        $qRCode = $config['host_name'] . '/shop/?r=weChat/we-chat/q-r-code-home&id=' . $fx_uid;
        $addFlag = Util::addQRCode($qRCode, $imgUrl, 1, true, false, $logo);
        if ($addFlag['flag'] == false) {
            return Util::returnArrEr('生成二维码失败！');
        }
        return Util::returnArrSu('', array('url' => $showUrl));
    }

    public static function getSignPackage($url)
    {
        $jsapiTicket = static::getJsApiTicket();
        // 注意 URL 一定要动态获取，不能 hardcode.
//        $url = "http://nwx.zhizhuchuxing.cn/web/shop/test.html";
        $timestamp = time();
        $nonceStr = WeChatPay::getNonceStr(16);
        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
        $signature = sha1($string);
        $config = Util::getWeChatConfig();
        $signPackage = array(
            "appId" => $config['appid'],
            "nonceStr" => $nonceStr,
            "timestamp" => $timestamp,
            "url" => $url,
            "signature" => $signature,
            "rawString" => $string
        );
        return $signPackage;
    }

    public static function getJsApiTicket()
    {
        // jsapi_ticket 应该全局存储与更新，以下代码以写入到文件中做示例
        $cache = \Yii::$app->cache;
        $data = $cache->get('jsapiticket');
        if (empty($data['expire_time']) || $data['expire_time'] < time()) {
            $accessToken = static::getAccessToken();
            // 如果是企业号用以下 URL 获取 ticket
            // $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
            $curl = new CurlInterface('', 5);
            $res = json_decode($curl->execute($url), true);
            $ticket = $res['ticket'];
            if ($ticket) {
                $data = [];
                $data['expire_time'] = time() + 7000;
                $data['jsapi_ticket'] = $ticket;
                $cache->set('jsapiticket', $data);
            }
        } else {
            $ticket = $data['jsapi_ticket'];
        }
        return $ticket;
    }

    /**
     * 发送自定义的模板消息
     * @param $toUser
     * @param $template
     * @param $url
     * @param $data
     * @param $appid string 默认当前系统的微信配置 ,可更换为 其他微信公众号的配置
     * @param string $topColor
     * @return bool
     */
    public static function sendWxTemplate($toUser, $template, $url, $data, $topColor = '#7B68EE', $appid = '')
    {
        if ($appid != '') {
            Util::setSiteConfig('entryAuthWeChat', $appid);//变更微信公众号配置
        }
        $wxConfig = Util::getWeChatConfig();
        $template_config = require ROOT_PATH.'/common/config/wechatConfig/wxInterface/'.$wxConfig['mch_id'].'/Wx.msg.template.config.php';
        if (empty($template_config[$template])){
            return false;
        }
        $template = array(
            'touser' => $toUser,
            'template_id' => $template_config[$template],
            'url' => $url,
            'topcolor' => $topColor,
            'data' => $data
        );
        $token = static::getAccessToken();
        $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . $token;
        $curl = new CurlInterface($template, 1);
        $dataRes = $curl->execute($url, 'post');
        if ($dataRes['errcode'] == 0) {
            return true;
        } else {
            return false;
        }
    }
}